package com.tanhua.server.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.tanhua.autoconfig.template.HuanXinTemplate;
import com.tanhua.commons.utils.Constants;
import com.tanhua.dubbo.api.*;
import com.tanhua.model.domain.Question;
import com.tanhua.model.domain.UserInfo;
import com.tanhua.model.dto.RecommendUserDto;
import com.tanhua.model.mongo.RecommendUser;
import com.tanhua.model.mongo.Visitors;
import com.tanhua.model.vo.ErrorResult;
import com.tanhua.model.vo.NearUserVo;
import com.tanhua.model.vo.PageResult;
import com.tanhua.model.vo.TodayBest;
import com.tanhua.server.exception.BusinessException;
import com.tanhua.server.interceptor.UserHolder;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;


@Service
public class TanhuaService {

    @DubboReference
    private RecommendUserApi recommendUserApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private QuestionApi questionApi;

    @Autowired
    private HuanXinTemplate huanXinTemplate;

    @Value("${tanhua.default.recommend.users}")
    private String recommendUser;

    @DubboReference
    private UserLikeApi userLikeApi;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired  // 添加好友的方法
    private MessagesService messagesService;

    @DubboReference  // 查询附近的用户
    private UserLocationApi userLocationApi;

    @DubboReference    // 保存访客记录
    private VisitorsApi visitorsApi;


    // 查询今日佳人数据
    public TodayBest todayBest() {
        // 获取用户id
        Long userId = UserHolder.getUserId();
        // 调用api查询
        RecommendUser recommendUser = recommendUserApi.queryWithMaxScore(userId);
        // 如果今日佳人等于null,设置一个默认值
        if (recommendUser == null) {
            recommendUser = new RecommendUser();
            recommendUser.setUserId(1L);
            recommendUser.setScore(99d);
        }
        // 将RecommendUser对象转化为todayBest对象,调用userInfo查询佳人的信息
        UserInfo userInfo = userInfoApi.findById(recommendUser.getUserId());
        // 创建TodayBest的对象,通过有参构造进行数据传递,在vo对象中设置了拷贝方法
        TodayBest vo = TodayBest.init(userInfo, recommendUser);
        // 返回
        return vo;
    }

    // 分页查询推荐好友列表
    public PageResult recommendation(RecommendUserDto dto) {
        // 1:获取用户id
        Long userId = UserHolder.getUserId();
        // 2:调用recommendUserApi分页查询数据列表 (PageResult  -- RecommendUser)
        PageResult pr = recommendUserApi.queryRecommendUserList(dto.getPage(), dto.getPagesize(), userId);
        // 3:获取分页中的RecommendUser数据列表
        List<RecommendUser> items = (List<RecommendUser>) pr.getItems();
        // 4:判断列表是否为空
        if (items == null) {
            return pr;
        }
        // 5:提取所有推荐的与用户id列表
        List<Long> ids = CollUtil.getFieldValues(items, "userId", Long.class);
        UserInfo userInfo = new UserInfo();
        // 往里面设置前端传过来的条件
        userInfo.setAge(dto.getAge());
        userInfo.setGender(dto.getGender());
        // 6:构建查询条件,批量查询所有的用户详情
        Map<Long, UserInfo> map = userInfoApi.findByIds(ids, userInfo);
        // 7:循环推荐的用户列表,构建vo对象
        List<TodayBest> list = new ArrayList<>();
        for (RecommendUser item : items) {
            UserInfo info = map.get(item.getUserId());
            if (info != null) {
                TodayBest vo = TodayBest.init(info, item);
                list.add(vo);
            }
        }
        pr.setItems(list);
        return pr;
    }

    // 查看佳人详情
    public TodayBest findPersonalInfo(Long userId) {
        // 1:根据用户id查询用户详情
        UserInfo userInfo = userInfoApi.findById(userId);
        // 2:根据构造人id和查看的用户id,查询两者的推荐数据
        RecommendUser user = recommendUserApi.queryByUserId(userId, UserHolder.getUserId());
        // 构造访客数据,调用api保存
        Visitors visitors = new Visitors();
        visitors.setUserId(userId);  // 被查看人的id
        visitors.setVisitorUserId(UserHolder.getUserId());  // 访问人的id
        visitors.setFrom("首页");  // 从哪里访问
        visitors.setDate(System.currentTimeMillis());  // 访问时间的毫秒值
        visitors.setVisitDate(new SimpleDateFormat("yyMMdd").format(new Date()));  // 设置来访时间,年月日
        visitors.setScore(user.getScore());  // 缘分值
        visitorsApi.save(visitors);
        // 3:构造返回值
        return TodayBest.init(userInfo, user);
    }

    // 根据用户id查询用户设置的问题
    public String findStrangerQuestions(Long userId) {
        Question question = questionApi.findByUserId(userId);
        return question == null ? "你喜欢风吗" : question.getTxt();
    }

    /**
     * 回复陌生人问题
     */
    public void replyQuestions(Long userId, String reply) {
        // 1:构造消息数据,调用JSON工具类转化
        Long currentUserId = UserHolder.getUserId();  // 当前登录用户的id
        UserInfo userInfo = userInfoApi.findById(currentUserId);  // 当前用户的详细信息
        Map map = new HashMap<>();
        map.put("userId", currentUserId);
        map.put("huanXinId", Constants.HX_USER_PREFIX + currentUserId);
        map.put("nickname", userInfo.getNickname());
        map.put("strangerQuestion", findStrangerQuestions(userId));
        map.put("reply", reply);
        // 调用JSON工具类转化
        String message = JSON.toJSONString(map);
        // 2:调用template对象,发送消息
        // 参数1:接收方的环信id,参数2:消息
        String userName = Constants.HX_USER_PREFIX + userId;
        Boolean sendMsg = huanXinTemplate.sendMsg(userName, message);
        if (!sendMsg) {
            throw new BusinessException(ErrorResult.error());
        }
    }


    // 探花,左滑右滑 -- 查询推荐用户列表
    public List<TodayBest> queryCardsList() {
        // 1:调用api查询推荐数据列表,(排除喜欢/不喜欢的用户,一次查询需要有数量限制)
        List<RecommendUser> users = recommendUserApi.queryCardsList(UserHolder.getUserId(), 10);
        // 2:判断数据是否存在,如果不存在,构建默认数据
        if (CollUtil.isEmpty(users)) {
            // 构建默认数据,可使用配置文件进行配置
            users = new ArrayList<>();
            String[] userIds = recommendUser.split(",");
            for (String userId : userIds) {
                RecommendUser user = new RecommendUser();
                user.setUserId(Convert.toLong(userId));
                user.setToUserId(UserHolder.getUserId());
                user.setScore(RandomUtil.randomDouble(60, 90));
            }
        }
        // 3:构造vo.返回查询结果
        List<Long> ids = CollUtil.getFieldValues(users, "userId", Long.class);
        Map<Long, UserInfo> infoMap = userInfoApi.findByIds(ids, null);
        List<TodayBest> vos = new ArrayList<>();
        for (RecommendUser user : users) {
            UserInfo userInfo = infoMap.get(user.getUserId());
            if (userInfo != null) {
                TodayBest best = TodayBest.init(userInfo, user);
                vos.add(best);
            }
        }
        return vos;
    }


    // 探花 -- 右滑喜欢功能
    public void likeUser(Long likeUserId) {
        // 1:调用api,保存喜欢数据(保存到MongoDB中)
        Boolean save = userLikeApi.saveOrUpdate(UserHolder.getUserId(), likeUserId, true);
        // 判断操作是否成功
        if (!save) {
            // 操作失败
            throw new BusinessException(ErrorResult.error());
        }
        // 2:操作Redis,写入喜欢的数据,删除不喜欢的数据,拥有两个集合(喜欢的集合,不喜欢的集合),redis中使用set集合
        redisTemplate.opsForSet().remove(Constants.USER_NOT_LIKE_KEY + UserHolder.getUserId(), likeUserId.toString());
        // 添加到redis中
        redisTemplate.opsForSet().add(Constants.USER_LIKE_KEY + UserHolder.getUserId(), likeUserId.toString());
        // 3:判断是否双向喜欢
        if (isLike(likeUserId, UserHolder.getUserId())) {
            // 4:添加好友
            messagesService.contacts(likeUserId);
        }
    }

    // 探花 -- 左滑不喜欢功能
    public void notLikeUser(Long likeUserId) {
        // 1:调用api,保存喜欢数据(保存到MongoDB中)
        Boolean save = userLikeApi.saveOrUpdate(UserHolder.getUserId(), likeUserId, false);
        // 判断操作是否成功
        if (!save) {
            // 操作失败
            throw new BusinessException(ErrorResult.error());
        }
        // 2:操作Redis,写入喜欢的数据,删除不喜欢的数据,拥有两个集合(喜欢的集合,不喜欢的集合),redis中使用set集合
        redisTemplate.opsForSet().add(Constants.USER_NOT_LIKE_KEY + UserHolder.getUserId(), likeUserId.toString());
        // 添加到redis中
        redisTemplate.opsForSet().remove(Constants.USER_LIKE_KEY + UserHolder.getUserId(), likeUserId.toString());
        // 3:判断是否双向喜欢
        if (isLike(likeUserId, UserHolder.getUserId())) {
            // 4:删除好友,同时删除环信好友
            messagesService.contacts(likeUserId);
        }
    }


    // 判断喜欢的集合中,是否包含likeUserId ,公共方法
    public boolean isLike(Long userId, Long likeUserId) {
        String key = Constants.USER_LIKE_KEY + userId;
        return redisTemplate.opsForSet().isMember(key, likeUserId.toString());
    }

    // 查询附近的人
    public List<NearUserVo> queryNearUser(String gender, String distance) {
        // 1:调用api查询附近的用户 (不能直接返回UserLocation对象,里面的GeoJsonPoint location字段不支持序列化)
        // 这里返回所有附近的人的用户id,会包含当前用户的id,将自己排除在外
        List<Long> userIds = userLocationApi.queryNearUser(UserHolder.getUserId(),Double.valueOf(distance));
        // 2:判断集合是否为空
        if (CollUtil.isEmpty(userIds)){
            return new ArrayList<>();
        }
        // 3:调用userInfoApi根据用户id,查询用户详情
        UserInfo userInfo = new UserInfo();
        userInfo.setGender(gender);
        Map<Long, UserInfo> map = userInfoApi.findByIds(userIds, userInfo);
        // 4:构造返回值
        List<NearUserVo> vos = new ArrayList<>();
        for (Long userId : userIds) {
            // 排除当前id
            if (userId == UserHolder.getUserId()){
                continue;
            }
            UserInfo info = map.get(userId);
            if (info != null){
                NearUserVo vo = NearUserVo.init(info);
                vos.add(vo);
            }
        }
        return vos;
    }
}

